<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>2.2.2_call和apply的用途</title>
  </head>
  <body>
    <script>
      // 1.改变this指向
      var obj1 = {
        name: 'sven',
      }
      var obj2 = {
        name: 'anne',
      }
      window.name = 'window'
      var getName = function () {
        console.log(this.name)
      }
      getName() // window
      getName.call(obj1) // sven
      getName.call(obj2) // anne
      console.log('--------------')
      // 2.Function.prototype.bind 实现
      // 2.1 简化版
      Function.prototype.bind = function (context) {
        var self = this // 保存当前对象
        return function () {
          return self.apply(context, arguments)
        }
      }
      var obj = {
        name: 'sven',
      }
      var func = function () {
        console.log(this.name) // sven
      }.bind(obj)
      func()
      console.log('--------------')
      // 2.2 复杂版
      Function.prototype.bind = function () {
        const self = this
        context = [].shift.call(arguments) // 需要绑定的this上下文
        args = [].slice.call(arguments) // 剩余参数转成数组
        return function () {
          return self.apply(
            context,
            [].concat.call(args, [].slice.call(arguments))
          )
        }
      }
      var obj = {
        name: 'sven',
      }
      var func = function (a, b, c, d) {
        console.log(this.name) // sven
        console.log([a, b, c, d]) // [1, 2, 3, 4]
      }.bind(obj, 1, 2)
      func(3, 4)
      console.log('--------------')
      // 3.借用其他对象的方法
      // 3.1 "借用构造函数"
      var A = function (name) {
        this.name = name
      }
      var B = function () {
        A.apply(this, arguments)
      }
      B.prototype.getName = function () {
        return this.name
      }
      var b = new B('sven')
      console.log(b.getName()) // sven
      console.log('--------------')
      // 3.2 操作"伪数组"对象
      ;(function () {
        Array.prototype.push.call(arguments, 3)
        console.log(arguments) // [1, 2, 3]
      })(1, 2)
    </script>
  </body>
</html>
